﻿
using Newtonsoft.Json.Linq;
using PushSharp.Apple;
using PushSharp.Core;
using PushSharp.Google;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using PetaPoco;
using AppManager.Model;

namespace PushTask
{
    internal class PushSharpSend
    {
        internal static void GcmSend(List<Message> list)
        {
            Database db = new Database();
            if (list == null || list.Count() == 0) return;
            var project = db.FirstOrDefault<Project>("select * from project where id=@0", list.FirstOrDefault().ProjectId);

            if (project == null) return;

            //如果未配置使用gcm,直接返回
            if (!project.IsUseGcm) return;
            //如果配置錯誤返回
            //if (project.GcmError) return;

            var senderId = project.SenderId;
            var authorizationToken = project.Token;
            var packageName = project.PackageName;
            var messageIds = list.Select(s => s.Id);

            if (string.IsNullOrEmpty(senderId) ||
                    string.IsNullOrEmpty(authorizationToken) ||
                    string.IsNullOrEmpty(packageName))
            {
                MessageDeviceBLL.SendFail_MessageIds(messageIds);

                LogHelper.WriteCreateNewLog(LogType.gcmError, project.Identity + " 未设置Project表中参数");
                db.Execute("update project set gcmerror=@0 , gcmexception=@1 and Id=@2", true, "未设置Project表中参数", project.Id);
                return;
            }


            GcmConfiguration config = null;
            try
            {
                #region 启动服务

                try
                {
                    config = new GcmConfiguration(
                            senderId,
                            authorizationToken,
                            packageName);
                }
                catch (Exception ex)
                {
                    db.Execute("update project set gcmerror=@0, gcmexception=@1", true, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "gcm配置錯誤" + ex.Message);
                    LogHelper.WriteCreateNewLog("gcm配置錯誤" + project.Identity, ex.Message);
                }

                var gcmBroker = new GcmServiceBroker(config);

                gcmBroker.OnNotificationFailed += (notification, aggregateEx) =>
                {
                    Exception exception = null;
                    aggregateEx.Handle(ex =>
                    {
                        if (ex is GcmNotificationException)
                        {
                            var nofificationException = (GcmNotificationException)ex;

                            var gcmNotification = nofificationException.Notification;
                            var description = nofificationException.Description;
                        }
                        else if (ex is GcmMulticastResultException)
                        {

                        }
                        //else if (ex is MessageDeviceSubscriptionExpiredException)
                        //{
                        //    var expiredException = (MessageDeviceSubscriptionExpiredException)ex;
                        //    var oldId = expiredException.OldSubscriptionId;
                        //    var newId = expiredException.NewSubscriptionId;

                        //    if (!string.IsNullOrEmpty(newId))
                        //    {
                        //        //设备的订阅Id改变了
                        //    }
                        //}
                        else if (ex is RetryAfterException)
                        {
                            //如果是这个错误，你需要停止发送消息，直到 重试时间，就是在重试时间之前没有办法发送了
                        }
                        exception = ex;
                        //指定该异常已处理
                        return true;
                    });
                    Notification(notification, false, exception);
                };

                gcmBroker.OnNotificationSucceeded += (notification) =>
                {
                    Notification(notification, true);
                };
                gcmBroker.Start();
                #endregion
                foreach (var m in list)
                {
                    var messageId = m.Id;
                    int devicetype = 0;
                    bool isUseGoogle = true;
                    var mv = MessageDeviceBLL.GetFirstDevice(messageId, devicetype, isUseGoogle);


                    if (mv != null)
                    {
                        var count = MessageDeviceBLL.GetDeviceCount(messageId, devicetype, isUseGoogle);
                        //Console.WriteLine("stratId:{0}  count:{1}", mv.Id, count);

                        List<DeviceData> devices = new List<DeviceData>();
                        int currentCount = 0;
                        int size = 10000;
                        int id = mv.Id;

                        //每隔一萬條獲取一次數據
                        do
                        {
                            devices = MessageDeviceBLL.GetDevices(id, messageId, devicetype, isUseGoogle, size);

                            currentCount += size;
                            id += size;
                            //Console.WriteLine(string.Format("currentCount:{0}    id:{1}", currentCount, id));

                            SendGcms_Devices(gcmBroker, devices, m);
                        } while (currentCount <= count);
                    }
                }
                gcmBroker.Stop();
            }
            catch (Exception ex)
            {
                LogHelper.WriteCreateNewLog(LogType.gcmError, "GcmSend中發生異常" + ex.Message);
                MessageDeviceBLL.SendFail_MessageIds(messageIds);
            }
        }

        private static void SendGcms_Devices(GcmServiceBroker gcmBroker, List<DeviceData> devicedatas, Message m)
        {
            Database db = new Database();
            List<int> successList = new List<int>();
            List<int> errorList = new List<int>();
            successList.Add(-1);
            errorList.Add(-1);

            try
            {
                var str = new AndroidData(m.Content, m.Data).ToString();

                foreach (var item in devicedatas)
                {
                    try
                    {
                        gcmBroker.QueueNotification(new GcmNotification
                        {
                            RegistrationIds = new List<string> { item.DeviceStr },
                            Data = JObject.Parse(str),
                            Tag = m.Id
                        });
                    }
                    catch (Exception ex)
                    {
                        LogHelper.WriteCreateNewLog(LogType.gcmError, ex.Message);
                        errorList.Add(item.Id);
                        continue;
                    }
                    successList.Add(item.Id);
                }
            }
            catch (Exception ex)
            {
                errorList.AddRange(devicedatas.Select(s => s.Id));
            }

            MessageDeviceBLL.SendFail_Ids(errorList);
            MessageDeviceBLL.SendSuccess_Ids(successList);
        }

        /// <summary>
        /// 發送同一個項目的所有消息
        /// </summary>
        /// <param name="path"></param>
        /// <param name="list"></param>
        /// <param name="successList"></param>
        /// <param name="errorList"></param>
        internal static void ApnsSend(string path, List<Message> list)
        {
            Database db = new Database();
            if (list == null || list.Count() == 0) return;
            var project = db.FirstOrDefault<Project>("select * from project where id=@0", list.FirstOrDefault().ProjectId);

            if (project == null) return;

            //如果該項目未配置使用apns,直接返回
            if (!project.IsUseApns) return;

            //如果ios配置發生錯誤,直接返回
            //if (project.ApnsError) return;

            string certpath = "", certpwd = "";
            ApnsConfiguration config = null;

            var messageIds = list.Select(s => s.Id);
            try
            {
                #region 配置問題
                try
                {
                    #region 配置开发版和正式版                
                    if (project.IsProduct)
                    {
                        certpath = path + project.CertUrl;
                        certpwd = project.CertPwd;
                        config = new ApnsConfiguration(
                            ApnsConfiguration.ApnsServerEnvironment.Production,
                            certpath,
                            certpwd);
                    }
                    else
                    {
                        certpath = path + project.SandBox_CertUrl;
                        certpwd = project.SandBox_CertPwd;

                        config = new ApnsConfiguration(
                            ApnsConfiguration.ApnsServerEnvironment.Sandbox,
                            certpath,
                            certpwd);
                    }
                    #endregion
                }
                catch (Exception ex)
                {
                    db.Execute("update project set ApnsError=@0 , ApnsException=@1 and Id=@2", true, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "apns配置錯誤" + ex.Message, project.Id);
                    LogHelper.WriteCreateNewLog("apns配置錯誤" + project.Identity, project.Identity + ex.Message);

                    MessageDeviceBLL.SendFail_MessageIds(messageIds);
                }
                #endregion

                #region 如果项目配置失败，为所有的设备都添加失败记录
                if (!string.IsNullOrEmpty(certpath) &&
                                !string.IsNullOrEmpty(certpwd))
                {

                    if (!File.Exists(certpath))
                    {
                        LogHelper.WriteCreateNewLog(LogType.apnsError, project.Identity + " 证书不存在");
                        return;
                    }
                }
                else
                {
                    MessageDeviceBLL.SendFail_MessageIds(messageIds);

                    LogHelper.WriteCreateNewLog(LogType.apnsError, project.Identity + " 未设置证书或密码");
                    return;
                }
                #endregion

                #region 启动服务
                var broker = new ApnsServiceBroker(config);
                broker.OnNotificationFailed += (notification, exception) =>
                {
                    Notification(notification, false, exception);
                };
                broker.OnNotificationSucceeded += (notification) =>
                {
                    Notification(notification, true);
                };
                broker.Start();
                #endregion

                foreach (var m in list)
                {
                    var messageId = m.Id;
                    int devicetype = 1;
                    bool isUseGoogle = false;
                    var mv = MessageDeviceBLL.GetFirstDevice(messageId, devicetype, isUseGoogle);


                    if (mv != null)
                    {
                        var count = MessageDeviceBLL.GetDeviceCount(messageId, devicetype, isUseGoogle);
                        //Console.WriteLine("stratId:{0}  count:{1}", mv.Id, count);

                        List<DeviceData> devices = new List<DeviceData>();
                        int currentCount = 0;
                        int size = 10000;
                        int id = mv.Id;

                        //每隔一萬條獲取一次數據
                        do
                        {
                            devices = MessageDeviceBLL.GetDevices(id, messageId, devicetype, isUseGoogle, size);

                            currentCount += size;
                            id += size;
                            //Console.WriteLine(string.Format("currentCount:{0}    id:{1}", currentCount, id));

                            SendApns_Devices(broker, devices, m);
                        } while (currentCount <= count);
                    }
                }

                broker.Stop();
            }
            catch (Exception ex)
            {
                LogHelper.WriteCreateNewLog(LogType.apnsError, "在ApnsSend中執行發生錯誤：" + ex.Message);
            }
        }

        private static void SendApns_Devices(ApnsServiceBroker broker, List<DeviceData> devicedatas, Message m)
        {
            Database db = new Database();
            List<int> successList = new List<int>();
            List<int> errorList = new List<int>();
            successList.Add(-1);
            errorList.Add(-1);

            try
            {
                #region 发送消息                                                        
                var str = new IosData(m.Content, m.Data).ToString();
                foreach (var item in devicedatas)
                {
                    try
                    {
                        broker.QueueNotification(new ApnsNotification
                        {
                            DeviceToken = item.DeviceStr.Trim(' ').Replace(" ", string.Empty),
                            Payload = JObject.Parse(str),
                            Tag = m.Id,
                        });
                    }
                    catch (Exception ex)
                    {
                        LogHelper.WriteCreateNewLog(LogType.apnsError, ex.Message);
                        errorList.Add(item.Id);
                        continue;
                    }
                    successList.Add(item.Id);
                }
                #endregion
            }
            catch (Exception ex)
            {
                LogHelper.WriteCreateNewLog(LogType.apnsError, "ApnsSend中循环list发生错误：" + ex.Message);
                errorList.AddRange(devicedatas.Select(s => s.Id));
            }

            MessageDeviceBLL.SendFail_Ids(errorList);
            MessageDeviceBLL.SendSuccess_Ids(successList);
        }

        /// <summary>
        /// 处理返回数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="notification"></param>
        /// <param name="isSuccess"></param>
        private static void Notification(INotification notification, bool isSuccess, Exception ex = null)
        {
            try
            {
                string devicetoken = "";
                int mId = 0;
                string message = string.Empty;
                if (notification is ApnsNotification)
                {
                    var notify = (ApnsNotification)notification;
                    devicetoken = notify?.DeviceToken;
                    int.TryParse(notify?.Tag?.ToString(), out mId);
                    if (ex != null)
                    {
                        DisplayException(ex, ref message);
                    }
                }
                else if (notification is GcmNotification)
                {
                    var gcmNotify = (GcmNotification)notification;
                    devicetoken = gcmNotify?.RegistrationIds[0];
                    int.TryParse(gcmNotify?.Tag?.ToString(), out mId);
                    if (ex != null)
                    {
                        DisplayException(ex, ref message);
                    }
                }
                Database db = new Database();
                if (isSuccess)
                {
                    //刪除MessageDevice
                    MessageDeviceBLL.SendSuccess(mId, devicetoken);
                }
                else
                {
                    //修改錯誤原因
                    MessageDeviceBLL.SendFail(mId, devicetoken, message);
                }

            }
            catch (Exception exception)
            {
                LogHelper.WriteCreateNewLog(LogType.notify, "Notification中發生異常" + exception.Message);
            }
        }

        private static void DisplayException(Exception ex, ref string msg)
        {
            if (ex != null)
            {
                msg += ex.Message + Environment.NewLine;
                DisplayException(ex.InnerException, ref msg);
            }
        }
    }
}
